package com.lazyframework.security.web.extra.weixin;

import com.lazyframework.commons.support.BasicResponseStatus;
import com.lazyframework.commons.support.ResponseModels;
import com.lazyframework.security.web.JwtClients;
import com.lazyframework.security.web.authentication.SecurityResponseStatus;
import com.lazyframework.security.web.authentication.UserDetails;
import com.lazyframework.security.web.authentication.filter.AbstractAuthenticationProcessingFilter;
import com.lazyframework.security.web.authentication.token.Authentication;
import com.lazyframework.security.web.exception.AuthenticationException;
import com.lazyframework.security.web.exception.UserNotFoundException;
import com.lazyframework.security.web.extra.weixin.WxAuthService.WxAuthType;
import com.lazyframework.security.web.util.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信OpenID登录过滤器
 * <p>
 * Create by 0x4D6E in 2020.09.09
 */
public class OpenIDAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private JwtClients jwtClients;

    /**
     * 微信登录请求地址
     */
    private AntPathRequestMatcher requestMatcher = new AntPathRequestMatcher("/auth/wx");

    public void setJwtClients(JwtClients jwtClients) {
        this.jwtClients = jwtClients;
    }

    @Override
    protected boolean requires(HttpServletRequest request) {
        return requestMatcher.matches(request);
    }

    @Override
    protected Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        String code = request.getParameter("code");

        // 网页授权登录时会携带state参数
        boolean isWebPageAuthentication = request.getParameterMap().containsKey("state");

        // 根据不同的请求方式new不同的token
        OpenIDAuthenticationToken token;
        if (!isWebPageAuthentication) {
            token = new OpenIDAuthenticationToken(WxAuthType.MINI_PROGRAM, code);
        } else {
            token = new OpenIDAuthenticationToken(WxAuthType.MEDIA_PLATFORM, code);
        }

        return authenticationManager().authenticate(token);
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletResponse response, AuthenticationException ae)
            throws IOException {
        if (ae instanceof OpenIDAuthenticationException) {
            OpenIDAuthenticationException we = (OpenIDAuthenticationException) ae;
            if (we.getErrcode().equals("40029")) {
                ResponseModels.print(response, OpenIDResponseStatus.INVALID_CODE, we.getErrmsg());
            } else {
                Map<String, String> data = new HashMap<>();
                data.put("errmsg", we.getErrmsg());
                data.put("errcode", we.getErrcode());
                ResponseModels.print(response, OpenIDResponseStatus.UNKNOWN_WX_AUTH_ERROR, data);
            }
        } else if (ae instanceof UserNotFoundException) {
            logger.error(ae);
            ResponseModels.print(response, SecurityResponseStatus.USERNAME_NOTFOUND);
        } else {
            logger.error(ae);
            ResponseModels.print(response, BasicResponseStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException {
        UserDetails userDetails = (UserDetails) authentication.principal();
        String token = jwtClients.encode(userDetails.getId());
        ResponseModels.print(response, BasicResponseStatus.OK, token);
    }
}
